package Army.unit;

import Army.BuildingAndUnit;
import Army.Bullet;
import GameObject.Sprite;
import GameObject.ValueBar;
import Global.ResourceManager;
import Main.SoundFactory;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;

public abstract class Unit extends BuildingAndUnit {

	protected static double rotateSpeed = pi / 6;
	static BufferedImage bloodImg = ResourceManager.getImage("ingame/blood");
	//ArrayList<Point> path = new ArrayList<>();
	int attackFrame;
	double rotationTarget = 0;
	Point finalPoint = null;
	Bullet bullet;
	int way = 0;
	int direction = 0;
	int walkTime = 0;

	public Unit() {
	}

	public void setDodgePoint(Point dodgePoint) {
		this.finalPoint = currentTarget;
		currentTarget = dodgePoint;
	}

	public void setDodgePoint(int way, int direction, int d) {
		this.finalPoint = currentTarget;

		if (walkTime < 1) {
			this.way = -this.way;
			this.direction = -this.direction;
		} else {
			walkTime = 0;
			if ((this.way != way) || this.direction == 0) {
				this.way = way;
				this.direction = direction;
			}
		}
		currentTarget = findDodgePosition(this.way, this.direction, d);
	}

	@Override
	public Sprite getHitedEffect(int x, int y) {
		Sprite spt = new Sprite(bloodImg, 5, 1, x, y);
		spt.setSequence(0);
		spt.setInnerPoint(new Point(10, 10));
		return spt;

	}
	static Color barBuildColor = new Color(0, 0, 1, 0.8f);
	static Color barBackColor = new Color(1, 1, 1, 0.3f);

	@Override
	public void setRotation(double rotation) {
		rotationTarget = normalizeAngle(rotation);
	}

	public double getRotation() {
		return sprite.getRotation();
	}

	public BuildingAndUnitState getState() {
		return state;
	}

	public boolean isFired() {
		return sprite.getFrame() == attackFrame;
	}

	public Bullet getBullet() {
		return null;
	}

	@Override
	public void draw(Graphics2D g, int dx, int dy) {
		g.setTransform(new AffineTransform());
		if (isSelected) {
			g.setColor(Color.WHITE);
			g.drawOval(sprite.getX() - size / 2 + dx, sprite.getY() - size / 2 + dy, size, size);
		}
		sprite.draw(g, dx, dy);
		if (!completed) {
			double value = (double) healthPoint / maxHealthPoint;
			int barWidth = 10;
			ValueBar bar = new ValueBar(barBackColor, barBuildColor, value, getPosition().x - size / 2, getPosition().y - barWidth / 2, size, barWidth);
			bar.draw(g, dx, dy);
		}
	}

	@Override
	public void update() {
		super.update();

		if (state == BuildingAndUnitState.DIE) {
			return;
		}
		run2TargetPosition();
		if (state == BuildingAndUnitState.RUN
				&& Math.abs(rotationTarget - getRotation()) < rotateSpeed) {
			int y = -(int) (speed * Math.cos(sprite.getRotation()));
			int x = (int) (speed * Math.sin(sprite.getRotation()));
			walkTime++;
			sprite.move(x, y);
		}

	}

	private void run2TargetPosition() {
		if (getRotation() != rotationTarget) {
			rotate2Target();
		}
		if (currentTarget != null) {

			double d = getPosition().distance(currentTarget);

			double r;
			if (state != BuildingAndUnitState.RUN && finalPoint != null) {
				r = getAngle(getPosition(), finalPoint);
			} else {
				r = getAngle(getPosition(), currentTarget);
			}
			rotationTarget = normalizeAngle(r);
			if (d < speed * 2) {
				if (finalPoint == null) {
					idle();
					currentTarget = null;
					way = 0;
					direction = 0;
				} else {
					currentTarget = finalPoint;
					finalPoint = null;
				}
			}
		}

	}

	public void rotate2Target() {

		double r = normalizeAngle(getRotation());
		double dr = Math.abs(r - rotationTarget);
		int a = 1;
		if (dr < rotateSpeed) {
			r = rotationTarget;
			sprite.setRotation(r);
			return;
		} else if (dr > pi) {
			a = -1;
		}
		if (r > rotationTarget) {
			r -= a * rotateSpeed;
		} else {
			r += a * rotateSpeed;
		}
		sprite.setRotation(r);
	}

	@Override
	public void die() {
		if (state == BuildingAndUnitState.DIE) {
			return;
		}
		
		state = BuildingAndUnitState.DIE;
		sprite.setSequence(getDieSequence());
	}

	@Override
	public void run() {
		if (state == BuildingAndUnitState.RUN || state == BuildingAndUnitState.DIE) {
			return;
		}
		state = BuildingAndUnitState.RUN;
		sprite.setSequence(getMoveSquence());
	}

	@Override
	public void idle() {
		if (state == BuildingAndUnitState.IDLE || state == BuildingAndUnitState.DIE) {
			return;
		}
		walkTime = 0;

		state = BuildingAndUnitState.IDLE;
		sprite.setSequence(getIdleSequence());
	}

	@Override
	public void attack() {
		if (state == BuildingAndUnitState.ATTACK || state == BuildingAndUnitState.DIE) {
			return;
		}
		state = BuildingAndUnitState.ATTACK;
		sprite.setSequence(getAttackSequence());
	}

	public void force(Point directionVector, double power) {
		double d = directionVector.distance(0, 0);
		int dx = (int) (power * directionVector.x / d);
		int dy = (int) (power * directionVector.y / d);
		move(dx, dy);
	}

	@Override
	public boolean isUnit() {
		return true;
	}

	public int[] getMoveSquence() {
		return null;
	}

	public int[] getIdleSequence() {
		return null;
	}

	public int[] getAttackSequence() {
		return null;
	}

	public int[] getDieSequence() {
		return null;
	}

	public boolean setLimit(int minX, int minY, int maxX, int maxY) {
		int x = sprite.getPosition().x;
		int y = sprite.getPosition().y;
		boolean isChanged = false;
		if (x < minX) {
			x = minX + 4;
			isChanged = true;
		} else if (x > maxX) {
			x = maxX - 4;
			isChanged = true;
		}
		if (y < minY) {
			y = minY + 4;
			isChanged = true;
		} else if (y > maxY) {
			y = maxY - 4;
			isChanged = true;
		}
		sprite.setPosition(x, y);
		return isChanged;
	}

	@Override
	public void setTarget(Point pos) {
		if (finalPoint == null) {
			currentTarget = pos;
		} else {
			finalPoint = pos;
		}
		/*way = 0;
		 direction = 0;*/
	}

	protected Point findDodgePosition(int way, int direction, int d) {

		int dx = 0;
		int dy = 0;
		if (way == 1 && direction == 1) {
			dx = d;
		} else if (way == 1 && direction == -1) {
			dx = -d;
		} else if (way == -1 && direction == 1) {
			dy = d;
		} else if (way == -1 && direction == -1) {
			dy = -d;
		}
		return new Point(getPosition().x + dx, getPosition().y + dy);
	}
}
